import { Destroyable, Event, ObjResettingWithEvent, reactJson } from "earthsdk3";
import { MyProjectManager } from "../MyProjectManager";
import { reqCreateClipPolygon, reqGetClipPolygon } from "@/api/modelser2Api";
import * as Cesium from 'cesium';
import { ESGeoPolygon, ESGeoRectangle, ESLocalCircle } from "earthsdk3";
import { ElMessage } from "element-plus";
import loading from "@/api/loading";
import { clippingMenuList } from "@/scripts/menu/modelser2/clippingMenuList";

// 圆
class CircleResettting extends Destroyable {
    constructor(clippingArea: ClippingArea, owner: MyProjectManager) {
        super();
        const sceneObject = owner.createSceneObject(ESLocalCircle) as ESLocalCircle
        sceneObject.fillGround = true;
        sceneObject.fillColor = [1, 0, 0, 0.5]
        let message: any

        this.ad(sceneObject.editingChanged.don(() => {
            if (sceneObject.editing) {
                message = ElMessage({
                    message: '1. 鼠标右键删除点进行编辑2. 点击空格键进行编辑方式的切换3. 双击鼠标左键或点击ESC键退出编辑',
                    duration: 0,
                    plain: true,
                })
            } else {
                message && message.close()
                clippingMenuList.value.map((i: any) => i.status = "none")
                if (sceneObject.position[0] == 0 && sceneObject.position[1] == 0 && sceneObject.position[2] == 0) return;
                // 如果不存在则添加新条目
                if (!clippingArea.clipMap.has(sceneObject.id)) {
                    // 编辑结束后  1.存储ESLocalCircle对象 2.设置水面蒙版列表
                    clippingArea.clipMap.set(sceneObject.id, sceneObject); // 不存在则添加新条目
                    // 根据原点和半径计算点位
                    const points = clippingArea.getCircularCoordinates(sceneObject.position, sceneObject.radius);
                    const geojson = clippingArea.setGeojson(points)
                    const item = {
                        "name": '裁剪边界' + (clippingArea.clipLists.length + 1),
                        "id": sceneObject.id,
                        "operation": 1,
                        "type": false,
                        "geojson": geojson
                    }
                    clippingArea.clipLists = [...clippingArea.clipLists, item]
                } else {
                    const item = clippingArea.clipLists.find((i: any) => i.id == sceneObject.id)
                    const points = clippingArea.getCircularCoordinates(sceneObject.position, sceneObject.radius);
                    item.geojson = clippingArea.setGeojson(points)
                    clippingArea.clipLists = [...clippingArea.clipLists]
                }

            }


        }))
        sceneObject.editing = true;


        this.ad(() => {
            if (sceneObject && (!clippingArea.clipMap.has(sceneObject.id))) {
                sceneObject.editing = false
                owner.destroySceneObject(sceneObject)
            }
            message && message.close()

        })
    }
}

// 矩形
class RectangleResettting extends Destroyable {
    constructor(clippingArea: ClippingArea, owner: MyProjectManager) {
        super();
        const sceneObject = owner.createSceneObject(ESGeoRectangle) as ESGeoRectangle
        sceneObject.fillGround = true;
        sceneObject.stroked = false
        sceneObject.fillColor = [1, 0, 0, 0.5]
        let message: any

        this.ad(sceneObject.editingChanged.don(() => {
            if (sceneObject.editing) {
                message = ElMessage({
                    message: '1. 鼠标右键删除点进行编辑2. 点击空格键进行编辑方式的切换3. 双击鼠标左键或点击ESC键退出编辑',
                    duration: 0,
                    plain: true,
                })
            } else {
                message && message.close()
                clippingMenuList.value.map((i: any) => i.status = "none")
                if (!sceneObject.points || sceneObject.points.length < 2) return;
                // 如果不存在则添加新条目
                if (!clippingArea.clipMap.has(sceneObject.id)) {
                    // 编辑结束后  1.存储ESLocalCircle对象 2.设置水面蒙版列表
                    clippingArea.clipMap.set(sceneObject.id, sceneObject); // 不存在则添加新条目
                    const points = clippingArea.setRectanglePoints(sceneObject.points)
                    const geojson = clippingArea.setGeojson(points)
                    const item = {
                        "name": '裁剪边界' + (clippingArea.clipLists.length + 1),
                        "id": sceneObject.id,
                        "operation": 1,
                        "type": false,
                        "geojson": geojson
                    }
                    clippingArea.clipLists = [...clippingArea.clipLists, item]
                } else {
                    const item = clippingArea.clipLists.find((i: any) => i.id == sceneObject.id)
                    const points = clippingArea.setRectanglePoints(sceneObject.points)
                    item.geojson = clippingArea.setGeojson(points)
                    clippingArea.clipLists = [...clippingArea.clipLists]
                }
            }
        }))
        sceneObject.editing = true;


        this.ad(() => {
            if (sceneObject && (!clippingArea.clipMap.has(sceneObject.id))) {
                sceneObject.editing = false
                owner.destroySceneObject(sceneObject)
            }
            message && message.close()
        })
    }
}

// 多边形
class PolygonResettting extends Destroyable {
    constructor(clippingArea: ClippingArea, owner: MyProjectManager) {
        super();
        const sceneObject = owner.createSceneObject(ESGeoPolygon) as ESGeoPolygon
        sceneObject.fillGround = true;
        sceneObject.stroked = false
        sceneObject.fillColor = [1, 0, 0, 0.5]
        let message: any
        this.ad(sceneObject.editingChanged.don(() => {
            if (sceneObject.editing) {
                message = ElMessage({
                    message: '1. 点击空格键进行编辑方式的切换2. 双击鼠标左键或点击ESC键退出编辑',
                    duration: 0,
                    plain: true,
                })
            } else {
                message && message.close()
                clippingMenuList.value.map((i: any) => i.status = "none")

                if (!sceneObject.points || sceneObject.points.length < 3) return;
                // 如果不存在则添加新条目
                if (!clippingArea.clipMap.has(sceneObject.id)) {
                    // 编辑结束后  1.存储ESLocalCircle对象 2.设置水面蒙版列表
                    clippingArea.clipMap.set(sceneObject.id, sceneObject); // 不存在则添加新条目
                    const geojson = clippingArea.setGeojson(sceneObject.points)
                    const item = {
                        "name": '裁剪边界' + (clippingArea.clipLists.length + 1),
                        "id": sceneObject.id,
                        "operation": 1,
                        "type": false,
                        "geojson": geojson
                    }
                    clippingArea.clipLists = [...clippingArea.clipLists, item]
                } else {
                    const item = clippingArea.clipLists.find((i: any) => i.id == sceneObject.id)
                    item.geojson = clippingArea.setGeojson(sceneObject.points)
                    clippingArea.clipLists = [...clippingArea.clipLists]
                }
            }
        }))
        sceneObject.editing = true;

        this.ad(() => {
            if (sceneObject && (!clippingArea.clipMap.has(sceneObject.id))) {
                sceneObject.editing = false
                owner.destroySceneObject(sceneObject)
            }
            message && message.close()

        })
    }
}
export class ClippingArea extends Destroyable {

    // 创建事件
    private _createEvent = this.ad(new Event<[string]>())
    get createEvent() { return this._createEvent }

    get tileServiceName() {
        return this._owner.modelser2Manager.eSMsTileset.tileServiceName;
    }

    get eSMsTileset() {
        return this._owner.modelser2Manager.eSMsTileset;
    }

    // 拾取处理
    private _selectResettting = this.dv(new ObjResettingWithEvent(this.createEvent, (res) => {
        switch (res) {
            case 'circle':
                return new CircleResettting(this, this._owner);
            case 'rectangle':
                return new RectangleResettting(this, this._owner);
            case 'polygon':
                return new PolygonResettting(this, this._owner);
            default:
                return undefined;
        }

    }))
    get selectResettting() { return this._selectResettting; }

    // 获取裁剪区域列表
    async getClipPolygon() {
        try {
            const res = await reqGetClipPolygon(this.tileServiceName)
            // @ts-ignore
            if (res.status !== 'ok') return;
            const data = res.data.map((item: any) => {
                return {
                    ...item,
                    type: item.operation == 2
                }
            })
            this.clipLists = data;
            this.setMap()
            console.log('裁剪区域列表', data);
        } catch (error) {
            console.error(error);
        }
    }
    setMap() {
        if (!this.clipLists.length) return;
        if (this.clipMap.size) {
            for (let e of this.clipMap) {
                const [id, esobj] = e;
                this._owner.destroySceneObject(esobj)
            }
            this.clipMap.clear();
        }
        for (let e of this.clipLists) {
            // map中不存在就创建
            if (!this.clipMap.has(e.id)) {
                this.setClipMap(e.geojson, e.id);
            }
        }
    }

    // 设置矩形点位
    setRectanglePoints(points: any) {
        const h = points[0][2] ? points[0][2] : 0
        return [
            [points[0][0], points[0][1], h],
            [points[1][0], points[0][1], h],
            [points[1][0], points[1][1], h],
            [points[0][0], points[1][1], h],
        ]
    }

    // 设置geojson
    setGeojson(points: any) {
        // const arr = points.map((item: any) => {
        //     return [item[0], item[1]]
        // })
        const arr = [...points]
        arr.push(arr[0])
        const geojson = {
            "type": "Polygon",
            "coordinates": [
                [...arr]
            ]
        }
        return JSON.stringify(geojson);
    }

    // 裁剪区域列表（提交后端的）
    private _clipLists = this.dv(reactJson<any>([]));
    get clipLists() { return this._clipLists.value; }
    get clipListsChanged() { return this._clipLists.changed; }
    set clipLists(value: any) { this._clipLists.value = value; }

    // 裁剪区域对应的三维对象（提交后端的）
    private _clipMap = new Map<string, any>();
    get clipMap() { return this._clipMap; }
    // 设置裁剪区域场景对象（提交后端的）
    setClipMap(geojsonStr: string, id: string,) {
        const geojson = JSON.parse(geojsonStr);
        const points = geojson.coordinates[0].map((item: any) => {
            // return [item[0], item[1], 0];
            const h = item[2] ? item[2] : 0;
            return [item[0], item[1], h];
        })
        // ui上创建的
        const sceneObject = this._owner.createSceneObject(ESGeoPolygon, id) as ESGeoPolygon;
        sceneObject.fillGround = true;
        sceneObject.fillColor = [0, 0, 1, 0.5];
        sceneObject.points = points

        let message: any
        sceneObject.ad(sceneObject.editingChanged.don(() => {
            if (sceneObject.editing) {
                message = ElMessage({
                    message: '1. 点击空格键进行编辑方式的切换2. 双击鼠标左键或点击ESC键退出编辑',
                    duration: 0,
                    plain: true,
                })
            } else {
                message && message.close()
                const item = this.clipLists.find((i: any) => i.id == sceneObject.id)
                item.geojson = this.setGeojson(sceneObject.points)
                this.clipLists = [...this.clipLists]
            }
        }))
        this.ad(() => message && message.close())
        this.clipMap.set(id, sceneObject); // 不存在则添加新条目
    }

    // 根据原点和半径计算圆形坐标
    getCircularCoordinates(point: [number, number, number], radius: number) {
        // 都是在笛卡尔坐标下进行计算的
        const sides = 36;
        const circlePoints = [] as [number, number, number][];
        if (radius <= 0 || sides <= 0) return []
        let Cartesian3_to_WGS84 = function (point: Cesium.Cartesian3): [number, number, number] {
            let cartesian33 = new Cesium.Cartesian3(point.x, point.y, point.z);
            let cartographic = Cesium.Cartographic.fromCartesian(cartesian33);
            let lat = Cesium.Math.toDegrees(cartographic.latitude);
            let lng = Cesium.Math.toDegrees(cartographic.longitude);
            let alt = cartographic.height;
            return [lng, lat, alt];
        }
        //法向量
        const normalVector = Cesium.Cartesian3.fromDegrees(...point);
        // 辅助向量
        const auxiliaryVectorZ = new Cesium.Cartesian3(0, 0, 1);
        const auxiliaryVectorX = new Cesium.Cartesian3(1, 0, 0);
        // 向量点乘结果为正负1就是平行
        const circleStartPoint = Cesium.Cartesian3.cross(
            normalVector,
            Math.abs(Cesium.Cartesian3.dot(normalVector, auxiliaryVectorZ)) != 1 ? auxiliaryVectorZ : auxiliaryVectorX,
            new Cesium.Cartesian3()
        );
        // 归一化，乘半径
        Cesium.Cartesian3.normalize(circleStartPoint, circleStartPoint);
        Cesium.Cartesian3.multiplyByScalar(circleStartPoint, radius, circleStartPoint);
        // 通过旋转，计算圆点结果
        for (let j = 0; j <= sides; j++) {
            //获取旋转矩阵
            let quat = Cesium.Quaternion.fromAxisAngle(normalVector, j * 2 * Math.PI / sides + Cesium.Math.toRadians(135));
            let rot_mat3 = Cesium.Matrix3.fromQuaternion(quat);
            let m = Cesium.Matrix4.fromRotationTranslation(rot_mat3, Cesium.Cartesian3.ZERO);
            Cesium.Matrix4.multiplyByTranslation(m, circleStartPoint, m);
            const startPoint = Cesium.Matrix4.getTranslation(m, new Cesium.Cartesian3());
            Cesium.Cartesian3.add(Cesium.Cartesian3.fromDegrees(...point), startPoint, startPoint);
            circlePoints.push(
                Cartesian3_to_WGS84(startPoint),
            )
        }
        return circlePoints;
    }

    // 添加裁剪区域
    async createClipPolygon() {
        try {
            const clipPolygons = this.clipLists.map((item: any) => {
                item.operation = item.type ? 2 : 1
                return item
            })
            const param = {
                "tileServiceName": this.tileServiceName,
                "clipPolygons": clipPolygons
            }
            const res = await reqCreateClipPolygon(param);
            // @ts-ignore
            if (res.status != 'ok') {
                loading.closeLoading()
                ElMessage({ message: "提交失败", type: 'error' })
                return;
            }
            loading.closeLoading()
            ElMessage({ message: "提交成功", type: 'success' })
            await this.getClipPolygon()
            this.eSMsTileset.refresh();


        } catch (error) {
            loading.closeLoading()
            console.error(error);
        }
    }

    clear() {
        this.createEvent.emit("");
        this.clipLists = []
        if (this.clipMap.size) {
            for (let e of this.clipMap) {
                const [id, esobj] = e;
                this._owner.destroySceneObject(esobj)
            }
            this.clipMap.clear();
        }
        clippingMenuList.value.map((i: any) => i.status = "none")

    }

    // 根据shp创建多边形
    createPolygonsByShp(data: any) {
        let masks: any = []
        data.features.map((item: any) => {
            const sceneObject = this._owner.createSceneObject(ESGeoPolygon) as ESGeoPolygon
            sceneObject.fillGround = true;
            sceneObject.stroked = false
            sceneObject.fillColor = [1, 0, 0, 0.5]
            sceneObject.points = item.exterior.map((e: any) => {
                return [e[0], e[1], e[2] ? e[2] : 0]
            })
            this.clipMap.set(sceneObject.id, sceneObject); // 不存在则添加新条目

            const m = {
                "name": item.prop[data.nameField].value,
                "id": sceneObject.id,
                "operation": 0,
                "type": true,
                "height": data.height,
                "geojson": this.setGeojson(sceneObject.points)
            }
            masks.push(m)
        })
        this.clipLists = [...this.clipLists, ...masks]
    }

    // 根据GeonJson创建多边形
    createPolygonsByGeonJson(data: any) {
        let masks: any = []
        data.features.map((item: any, index: number) => {
            const sceneObject = this._owner.createSceneObject(ESGeoPolygon) as ESGeoPolygon
            sceneObject.fillGround = true;
            sceneObject.stroked = false
            sceneObject.fillColor = [1, 0, 0, 0.5]
            sceneObject.points = item.exterior.map((e: any) => {
                return [e[0], e[1], e[2] ? e[2] : 0]
            })
            this.clipMap.set(sceneObject.id, sceneObject); // 不存在则添加新条目
            const num = this.clipLists.length + 1 + index
            const m = {
                "name": "水面蒙版" + num,
                "id": sceneObject.id,
                "operation": 0,
                "type": true,
                "height": data.height,
                "geojson": this.setGeojson(sceneObject.points)
            }
            masks.push(m)
        })
        this.clipLists = [...this.clipLists, ...masks]
    }

    constructor(private _owner: MyProjectManager) {
        super();
    }
}